INCLUDE(CMakeForceCompiler)
# CROSS COMPILER SETTING
cmake_minimum_required (VERSION 3.5)
SET(CMAKE_SYSTEM_NAME Generic)

project(mbedPal)

macro(SET_COMPILER_DBG_RLZ_FLAG flag value)
    SET(${flag}_DEBUG "${${flag}_DEBUG} ${value}")
    SET(${flag}_RELEASE "${${flag}_RELEASE} ${value}")

#enable this if for debugging
if (0)
 message("flag = ${flag}")
 message("value = ${value}")
 message("MY_C_FLAGS_RELEASE2 = ${CMAKE_C_FLAGS_RELEASE}")
endif(0) # comment end

endmacro(SET_COMPILER_DBG_RLZ_FLAG)

if(DISALLOW_WARNINGS)
    if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
        SET_COMPILER_DBG_RLZ_FLAG (CMAKE_C_FLAGS "-Werror")
        SET_COMPILER_DBG_RLZ_FLAG (CMAKE_CXX_FLAGS "-Werror")
    endif()
endif()

MACRO(HEADER_DIRECTORIES return_list)
  FILE(GLOB_RECURSE new_list ${CMAKE_CURRENT_SOURCE_DIR}/Configs/pal_config/${OS_BRAND}/*.h)
  SET(dir_list "")
  FOREACH(file_path ${new_list})
      GET_FILENAME_COMPONENT(dir_path ${file_path} PATH)
      SET(dir_list ${dir_list} ${dir_path})
  ENDFOREACH()
  LIST(REMOVE_DUPLICATES dir_list)
  SET(${return_list} ${dir_list})
ENDMACRO()

set(config_list "")
HEADER_DIRECTORIES(config_list)
foreach(config_dir ${config_list})
  ADD_GLOBALDIR("${config_dir}")
endforeach()

ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/Configs/pal_config)

include_directories(Port/Platform-API)

# This is so other modules could include pal.h
ADD_GLOBALDIR( ${CMAKE_CURRENT_SOURCE_DIR}/Source/PAL-Impl/Services-API)

# Add the current the directory of this of this file as a global dir pal.h could include more qualified paths
# and modules that use PAL could still include pal.h
ADD_GLOBALDIR( ${CMAKE_CURRENT_SOURCE_DIR}/Source)

set (PAL_MODULES_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Source/PAL-Impl/Modules)
set (PAL_PORT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Source/Port/Reference-Impl/OS_Specific/${OS_BRAND})
set (PAL_PORT_GENERIC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Source/Port/Reference-Impl/Generic)

set(PAL_SRCS
    ${PAL_MODULES_SOURCE_DIR}/Update/pal_update.c
    ${PAL_MODULES_SOURCE_DIR}/Storage/Flash/pal_internalFlash.c
    ${CMAKE_CURRENT_SOURCE_DIR}/Source/PAL-Impl/pal_init.c
)

# For Linux OS we will maintain backwards compatibility with the porting layer.
# This does cause limitations on the porting flexibility for Linux.

if(${OS_BRAND} MATCHES "Linux")
    file(WRITE dummy.c "int pal_cmake_dummy_reference_for_building(void) { return 0; }")
    #add library to build
    add_library(PLATFORM_LIBS STATIC dummy.c)
    add_dependencies(PLATFORM_LIBS mbedtls mbedcrypto mbedx509)
    target_link_libraries(PLATFORM_LIBS mbedtls mbedcrypto mbedx509 pthread rt)
    message("Autogenerated PLATFORM_LIBS for ${OS_BRAND}.")
    set(PAL_USE_PLATFORM_UPDATE 1)
    set(PAL_USE_PLATFORM_FILESYSTEM 1)
    add_definitions(-DPAL_USE_PLATFORM_FILESYSTEM=1)
endif()

if(PAL_USE_PLATFORM_UPDATE)
    set(PAL_SRCS ${PAL_SRCS} ${PAL_PORT_SOURCE_DIR}/Update/pal_plat_update.c)
    message("PAL is using update.")
else()
    message("PAL update disabled.")
endif()

if (PAL_USE_PLATFORM_INTERNAL_FLASH)
    set (PAL_SRCS ${PAL_SRCS} ${PAL_PORT_SOURCE_DIR}/Storage/Flash/pal_plat_internalFlash.c)
    message("PAL is using internal flash.")
else()
    message("PAL internal flash disabled.")
endif()

set(PAL_RTOS_SRCS
    ${PAL_MODULES_SOURCE_DIR}/RTOS/pal_rtos.c
    ${PAL_PORT_SOURCE_DIR}/Board_Specific/TARGET_${MBED_CLOUD_CLIENT_DEVICE}/pal_plat_${MBED_CLOUD_CLIENT_DEVICE}.c
    ${PAL_PORT_SOURCE_DIR}/RTOS/pal_plat_rtos.c
)
if (${OS_BRAND} MATCHES "Linux")
    set(PAL_RTOS_SRCS ${PAL_RTOS_SRCS} ${PAL_PORT_SOURCE_DIR}/Board_Specific/pal_plat_linux_common.c)
endif()

set(PAL_FILESYSTEM_SRCS
    ${PAL_MODULES_SOURCE_DIR}/Storage/FileSystem/pal_fileSystem.c
    ${PAL_PORT_GENERIC_SOURCE_DIR}/Storage/FileSystem/pal_plat_fileSystem_FsOverRam.c
)

if (PAL_USE_PLATFORM_FILESYSTEM)
    set (PAL_FILESYSTEM_SRCS ${PAL_FILESYSTEM_SRCS} ${PAL_PORT_SOURCE_DIR}/Storage/FileSystem/pal_plat_fileSystem.c)
    message("PAL is using filesystem.")
else()
    message("PAL filesystem disabled.")
endif()


set(PAL_NETWORKING_SRCS
    ${PAL_MODULES_SOURCE_DIR}/Networking/pal_network.c
    ${PAL_PORT_SOURCE_DIR}/Networking/${NETWORK_STACK}/pal_plat_network.c
)
if (${OS_BRAND} MATCHES "Zephyr")
    set(PAL_NETWORKING_SRCS
        ${PAL_NETWORKING_SRCS}
        ${PAL_PORT_SOURCE_DIR}/Networking/${NETWORK_STACK}/fd_work_poll.c
        ${PAL_PORT_SOURCE_DIR}/Networking/${NETWORK_STACK}/fd_work_poll_polling.c
    )
endif()

set(PAL_TLS_SRCS
    ${PAL_MODULES_SOURCE_DIR}/TLS/pal_TLS.c
    ${PAL_PORT_SOURCE_DIR}/../../Lib_Specific/${TLS_LIBRARY}/TLS/pal_plat_TLS.c
)

set(PAL_DRBG_SRCS
    ${PAL_MODULES_SOURCE_DIR}/DRBG/pal_drbg.c
    # XXX: following file is in completely wrong place, it is tied to SOTP, not MBEDTLS
)

set(PAL_ROT_SRCS
    ${PAL_MODULES_SOURCE_DIR}/ROT/pal_rot.c
)

set(PAL_ENTROPY_SRCS
    ${PAL_MODULES_SOURCE_DIR}/Entropy/pal_entropy.c
)

set(PAL_TIME_SRCS
    ${PAL_MODULES_SOURCE_DIR}/Time/pal_time.c
)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEVICE_FLASH")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEVICE_FLASH -std=gnu99")


# XXX: The mbedtls is configured as mbedTLS in PAL, which is not the correct name of the actual library.
# So we need to make it lowercase and add dependency using that.
string(TOLOWER ${TLS_LIBRARY} TLS_LINK_LIBRARY)
message("PAL using tls library ${TLS_LINK_LIBRARY}.")


# TODO: conditionalize the next two additions with a option, but currently the SOTP is welded in tightly

# Add the time-module, which is generic enough to use on all platforms
set (PAL_TIME_SRCS ${PAL_TIME_SRCS} ${PAL_PORT_GENERIC_SOURCE_DIR}/Time/pal_plat_time.c)

# Add the platform dependent ROT implementation, which gets used if the PAL_USE_HW_ROT==1
set (PAL_ROT_SRCS ${PAL_ROT_SRCS} ${PAL_PORT_GENERIC_SOURCE_DIR}/ROT/External/pal_plat_rot_hw.c)
# Add the platform independent ROT implementation, which gets used if the PAL_USE_HW_ROT==0
set (PAL_ROT_SRCS ${PAL_ROT_SRCS} ${PAL_PORT_GENERIC_SOURCE_DIR}/ROT/SOTP/pal_plat_rot_sotp.c)
# Add the platform independent ROT implementation for PSA, which gets used if the PAL_USE_HW_ROT==0
set (PAL_ROT_SRCS ${PAL_ROT_SRCS} ${PAL_PORT_GENERIC_SOURCE_DIR}/ROT/PSA/pal_plat_rot_psa.c)

# Add the platform independent ROT implementation for KVSTORE platform, which gets used if the PAL_USE_HW_ROT==0
# TODO: the code is really in wrong place for generic implementation
set (PAL_ROT_SRCS ${PAL_ROT_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/Source/Port/Reference-Impl/OS_Specific/mbedOS/ROT/pal_plat_rot.cpp)

# Add the platform independent DRBG implementation
set (PAL_DRBG_SRCS ${PAL_DRBG_SRCS} ${PAL_PORT_GENERIC_SOURCE_DIR}/DRBG/SOTP/pal_plat_drbg_sotp.c)

# Add the platform independent entropy implementation for SOTP
set (PAL_ENTROPY_SRCS ${PAL_ENTROPY_SRCS} ${PAL_PORT_GENERIC_SOURCE_DIR}/Entropy/SOTP/pal_plat_entropy_sotp.c)
# Add the platform independent entropy implementation for PSA
set (PAL_ENTROPY_SRCS ${PAL_ENTROPY_SRCS} ${PAL_PORT_GENERIC_SOURCE_DIR}/Entropy/PSA/pal_plat_entropy_psa.c)

# Add the platform independent flash-over-filesystem implementation, which gets used if
# PAL_SIMULATOR_FLASH_OVER_FILE_SYSTEM==1
set (PAL_SRCS ${PAL_SRCS} ${PAL_PORT_GENERIC_SOURCE_DIR}/Storage/Flash/pal_plat_internalFlash_FlashOverFilesystem.c)

# Add the platform independent noise implementation (used by the DRBG mdule)
set (PAL_DRBG_SRCS ${PAL_DRBG_SRCS} ${PAL_PORT_GENERIC_SOURCE_DIR}/DRBG/pal_plat_drbg_noise.c)

# Add PSA implementation for generating random buffer
set (PAL_DRBG_SRCS ${PAL_DRBG_SRCS} ${PAL_PORT_GENERIC_SOURCE_DIR}/DRBG/PSA/pal_plat_drbg_psa.c)

# Add DRBG support for targets with KVStore on non-mbed-os and non-Linux targets
set (PAL_DRBG_SRCS ${PAL_DRBG_SRCS} ${PAL_PORT_SOURCE_DIR}/../../Lib_Specific/${TLS_LIBRARY}/DRBG/pal_plat_drbg_w_entropy_sources.c)
set (PAL_DRBG_SRCS ${PAL_DRBG_SRCS} ${PAL_PORT_GENERIC_SOURCE_DIR}/DRBG/KVSTORE/pal_plat_drbg_kvstore.cpp)

# Create the RTOS module library
add_library(palRTOS STATIC "${PAL_RTOS_SRCS}")

# Create the filesystem module library
add_library(palFilesystem STATIC "${PAL_FILESYSTEM_SRCS}")

# Create the Networking module library
add_library(palNetworking STATIC "${PAL_NETWORKING_SRCS}")

# Create the ROT module library
add_library(palROT STATIC "${PAL_ROT_SRCS}")

# Add dependency for pal rot library only for FreeRTOS
#TODO: check what configuration needed to change this to kvstore dependency
if(${OS_BRAND} MATCHES "FreeRTOS")
add_dependencies(palROT sotp)
target_link_libraries(palROT sotp)
endif()

# Create the Entropy module library
add_library(palEntropy STATIC "${PAL_ENTROPY_SRCS}")


# Create the TLS module library
add_library(palTLS STATIC "${PAL_TLS_SRCS}")
add_dependencies(palTLS palTime key-config-manager nanostackeventloop palDRBG PLATFORM_LIBS)
target_link_libraries(palTLS palTime key-config-manager nanostackeventloop palDRBG PLATFORM_LIBS)

# Create the DRBG module library
add_library(palDRBG STATIC "${PAL_DRBG_SRCS}")
add_dependencies(palDRBG palRTOS)
target_link_libraries(palDRBG palRTOS)


# Create the Time module library, add dependency to fcc (or storage inside it)
add_library(palTime STATIC "${PAL_TIME_SRCS}")
add_dependencies(palTime fccstorage)
target_link_libraries(palTime fccstorage)

# Create Platform module internally if files are part of PAL implementation
if (EXISTS ${PAL_PORT_SOURCE_DIR}/Platform)
  file(GLOB PLATFORM_SRCS
    ${PAL_PORT_SOURCE_DIR}/Platform/*.c
    ${PAL_PORT_SOURCE_DIR}/Platform/*.cpp
  )
  add_library(PLATFORM_LIBS STATIC ${PLATFORM_SRCS})
  target_include_directories(PLATFORM_LIBS PUBLIC ${PAL_PORT_SOURCE_DIR}/Platform)
endif()

# Create the main PAL library
add_library(pal STATIC "${PAL_SRCS}")

# Linux platform does not support KVStore
if (NOT (${OS_BRAND} MATCHES "Linux"))
# Add dependency to KVStore and FCC so they will be built before and linked with PAL into final executable.
add_dependencies(pal palRTOS palNetworking  palDRBG palROT palEntropy palTLS palTime sotp PLATFORM_LIBS)
target_link_libraries(pal palRTOS palNetworking  palDRBG palROT palEntropy palTLS palTime sotp PLATFORM_LIBS)
else()
# Add dependency to SOTP and FCC so they will be built before and linked with PAL into final executable.
add_dependencies(pal palRTOS palNetworking  palDRBG palROT palEntropy palTLS palTime sotp nanostacklibservice PLATFORM_LIBS)
target_link_libraries(pal palRTOS palNetworking  palDRBG palROT palEntropy palTLS palTime sotp nanostacklibservice PLATFORM_LIBS)
endif()

# Bring in the ROT implementation from platform-common/application side. This can be
# empty also, selection is done based on PAL_USE_HW_ROT: if it is 0, then the pal_rot.c will need
# a pal_plat_osGetRoTFromHW() from this library.
if (PAL_USE_PLATFORM_ROT_OVERRIDE)
    # Use application-specific ROT implementation.
    add_dependencies(palROT platformROT)
    target_link_libraries(palROT platformROT)
endif()

# Add test CMakeList.txt
if(NOT DEFINED DISABLE_PAL_TESTS)
    ADD_SUBDIRECTORY(Test ${CMAKE_CURRENT_BINARY_DIR}/Test)
    get_directory_property(hasParent PARENT_DIRECTORY)
    if(hasParent)
        set (SRC_LIBS ${SRC_LIBS} PARENT_SCOPE)
        set (TEST_LIBS ${TEST_LIBS} PARENT_SCOPE)
    endif()
endif()
